<template>
  <div class="chat-box" @click="closeRefBox()" @mousemove="readedMessage()">
    <el-container>
      <el-header style="height: 50px" class="drag-box">
        <span>{{ title }}</span>
        <span
          :title="$t('群聊信息')"
          v-show="this.chat.type == 'GROUP'"
          class="btn-side el-icon-more drag-box-none"
          @click="showSide = !showSide"
        ></span>
        <dragBar></dragBar>
      </el-header>
      <el-main style="padding: 0" class="drag-box-none">
        <el-container>
          <el-container class="content-box">
            <el-main
              @mousedown.prevent="startDrag"
              :style="{ height: topDivHeight + 'px' }"
              class="draggable im-chat-main"
              id="chatScrollBox"
              @scroll="onScroll"
            >
              <div class="im-chat-box">
                <ul>
                  <el-checkbox-group v-model="radioArray">
                    <li
                      style="position: relative"
                      v-for="(msgInfo, idx) in chat.messages"
                      :key="idx"
                    >
                      <el-checkbox
                        v-if="
                          isMultiple &&
                          msgInfo.type !== $enums.MESSAGE_TYPE.TIP_TIME &&
                          msgInfo.type !== $enums.MESSAGE_TYPE.RECALL &&
                          msgInfo.type !== $enums.MESSAGE_TYPE.TIP_TEXT
                        "
                        class="checkboxx"
                        :label="msgInfo.id"
                      >
                        <span class="hiddenLabel"></span>
                      </el-checkbox>
                      <chat-message-item
                        v-if="idx >= showMinIdx"
                        @call="onCall(msgInfo.type)"
                        :id="msgInfo.id"
                        :active="activeMessageIdx == msgInfo.id"
                        :mine="msgInfo.sendId == mine.id"
                        :headImage="headImage(msgInfo)"
                        :showName="showName(msgInfo)"
                        :msgInfo="msgInfo"
                        :quoteShowName="showName(msgInfo.quoteMessage)"
                        :groupMembers="groupMembers"
                        @locateQuote="onLocateQuoteMessage"
                        @delete="deleteMessage"
                        @copy="copyMessage"
                        @recall="recallMessage"
                        @share="openShareFriend"
                        @download="downloadMessage"
                        @quote="onQuoteMessage"
                        :avatarDisabled="
                          chat.type == 'GROUP' &&
                          group.isForbidFriend &&
                          !isOwner
                        "
                        @showMessageAndBurn="showMessageAndBurn"
                      >
                      </chat-message-item>
                    </li>
                  </el-checkbox-group>
                </ul>
              </div>
              <!-- <div class="resizer" @mousedown="startDrag"></div> -->
            </el-main>

            <!-- 修改------0424 -->
            <el-footer
              :style="{ height: bottomDivHeight + 'px' }"
              class="im-chat-footer"
              v-if="!isMultiple"
            >
              <div class="chat-tool-bar" @mousedown="startDrag">
                <div
                  :title="$t('表情')"
                  class="icon iconfont icon-emoji"
                  ref="emotion"
                  @click.stop="showEmotionBox()"
                ></div>
                <div :title="$t('发送图片')">
                  <file-upload
                    :action="'/user/upload/image'"
                    :maxSize="10 * 1024 * 1024"
                    :fileTypes="[
                      'image/jpeg',
                      'image/png',
                      'image/jpg',
                      'image/webp',
                      'image/gif',
                    ]"
                    @before="onImageBefore"
                    @success="onImageSuccess"
                    @fail="onImageFail"
                  >
                    <i class="el-icon-picture-outline"></i>
                  </file-upload>
                </div>
                <div title="发送视频">
                  <file-upload
                    :action="'/user/upload/video'"
                    :maxSize="200 * 1024 * 1024"
                    :fileTypes="['video/mp4', 'video/ogg', 'video/webm']"
                    @before="onVideoBefore"
                    @success="onVideoSuccess"
                    @fail="onVideoFail"
                  >
                    <i class="el-icon-film"></i>
                  </file-upload>
                </div>
                <div title="发送文件">
                  <file-upload
                    ref="fileUpload"
                    :action="'/user/upload/file'"
                    :maxSize="200 * 1024 * 1024"
                    @before="onFileBefore"
                    @success="onFileSuccess"
                    @fail="onFileFail"
                  >
                    <i class="el-icon-wallet"></i>
                  </file-upload>
                </div>
                <div
                  title="回执消息"
                  v-show="chat.type == 'GROUP'"
                  class="icon iconfont icon-receipt"
                  :class="isReceipt ? 'chat-tool-active' : ''"
                  @click="onSwitchReceipt"
                ></div>
                <div
                  title="发送语音"
                  class="el-icon-microphone"
                  @click="showRecordBox()"
                ></div>
                <div
                  title="语音通话"
                  v-show="chat.type == 'PRIVATE'"
                  class="el-icon-phone-outline"
                  @click="showPrivateVideo('voice')"
                ></div>
                <div
                  title="语音通话"
                  v-show="chat.type == 'GROUP'"
                  class="el-icon-phone-outline"
                  @click="onGroupVideo()"
                ></div>
                <div
                  title="视频通话"
                  v-show="chat.type == 'PRIVATE'"
                  class="el-icon-video-camera"
                  @click="showPrivateVideo('video')"
                ></div>
                <div
                  title="聊天记录"
                  class="el-icon-chat-dot-round"
                  @click="showHistoryBox()"
                ></div>
                <div
                  title="阅后即焚"
                  class="shannon-iconfont shannon-huo"
                  :class="{ huo_active: $store.state.chatStore.checked }"
                  @click="changeBurn()"
                ></div>
                <div
                  title="清空自己发的消息(双方)"
                  class="shannon-iconfont shannon-shanchu"
                  v-if="chat.type == 'PRIVATE'"
                  @click="deleteMyMessage()"
                ></div>
              </div>
              <!-- <div class="send-content-area">
								<ChatInput :ownerId="group.ownerId" ref="chatInputEditor" :group-members="groupMembers"
									@submit="sendMessage" />
								<div class="send-btn-area">
									<el-button type="primary" icon="el-icon-s-promotion"
										@click="notifySend()">发送</el-button>
								</div>
							</div> -->
              <div class="send-content-area">
                <ChatInput
                  :ownerId="group.ownerId"
                  ref="chatInputEditor"
                  :group-members="groupMembers"
                  @submit="sendMessage"
                />
                <div v-if="quoteMessage" class="quote-message">
                  <chat-quote-message
                    :showName="showName(quoteMessage)"
                    :msgInfo="quoteMessage"
                  >
                  </chat-quote-message>
                  <div class="quote-remove" @click="onQuoteMessage(null)">
                    <i class="el-icon-close"></i>
                  </div>
                </div>
                <div class="send-btn-area">
                  <el-button
                    type="primary"
                    icon="el-icon-s-promotion"
                    @click="notifySend()"
                    >发送</el-button
                  >
                </div>
              </div>
            </el-footer>
            <el-footer
              :style="{ height: bottomDivHeight + 'px' }"
              class="im-chat-footer"
              v-if="isMultiple"
            >
              <div
                class="chat-tool-bar"
                style="
                  height: 100%;
                  display: flex;
                  justify-content: center;
                  align-items: center;
                  position: relative;
                "
              >
                <div class="btn-box">
                  <el-button
                    type="info"
                    icon="el-icon-position"
                    circle
                    @click="shareMultiple"
                  ></el-button>
                  <span>转发</span>
                </div>
                <div class="btn-box">
                  <el-button
                    type="info"
                    icon="el-icon-delete"
                    circle
                  ></el-button>
                  <span>删除</span>
                </div>
                <el-button
                  style="position: absolute; right: 80px"
                  v-if="isMultiple"
                  type="primary"
                  @click="deleteMultiple"
                  >取消</el-button
                >
              </div>
            </el-footer>
          </el-container>
          <el-aside class="chat-group-side-box" width="260px" v-if="showSide">
            <chat-group-side
              :group="group"
              :groupMembers="groupMembers"
              @reload="loadGroup(group.id)"
            >
            </chat-group-side>
          </el-aside>
        </el-container>
      </el-main>
      <add-group-member
        :visible="showAddGroupMember"
        :groupId="1"
        :members="[]"
        @share="shareMessage"
        @close="onCloseAddGroupMember"
      ></add-group-member>
      <emotion ref="emoBox" @emotion="onEmotion"></emotion>
      <chat-record
        :visible="showRecord"
        @close="closeRecordBox"
        @send="onSendRecord"
      ></chat-record>
      <group-member-selector
        ref="rtcSel"
        :groupId="group.id"
        @complete="onInviteOk"
      ></group-member-selector>
      <rtc-group-join ref="rtcJoin" :groupId="group.id"></rtc-group-join>
      <chat-history
        :visible="showHistory"
        :chat="chat"
        :friend="friend"
        :group="group"
        :groupMembers="groupMembers"
        @close="closeHistoryBox"
      ></chat-history>
    </el-container>
  </div>
</template>

<script>
import ChatGroupSide from "./ChatGroupSide.vue";
import ChatMessageItem from "./ChatMessageItem.vue";
import FileUpload from "../common/FileUpload.vue";
import Emotion from "../common/Emotion.vue";
import ChatRecord from "./ChatRecord.vue";
import ChatHistory from "./ChatHistory.vue";
import ChatAtBox from "./ChatAtBox.vue";
import GroupMemberSelector from "../group/GroupMemberSelector.vue";
import RtcGroupJoin from "../rtc/RtcGroupJoin.vue";
import ChatInput from "./ChatInput";
import dragBar from "@/view/components/dragBar";
import AddGroupMember from "@/view/components/AddGroupMember.vue";
import * as clipboard from "clipboard-polyfill";
import ChatQuoteMessage from "./ChatQuoteMessage.vue";

export default {
  name: "chatPrivate",
  components: {
    ChatInput,
    ChatMessageItem,
    FileUpload,
    ChatGroupSide,
    Emotion,
    ChatRecord,
    ChatHistory,
    ChatAtBox,
    GroupMemberSelector,
    RtcGroupJoin,
    AddGroupMember,
    ChatQuoteMessage,
    dragBar,
  },
  props: {
    chat: {
      type: Object,
    },
    sendProduct: {
      type: Boolean,
    },
  },
  data() {
    return {
      radioArray: [],
      friend: {},
      group: {},
      userInfo: {},
      groupMembers: [],
      sendImageUrl: "",
      sendImageFile: "",
      placeholder: "",
      activeMessageIdx: -1,
      isReceipt: true,
      showRecord: false, // 是否显示语音录制弹窗
      showSide: false, // 是否显示群聊信息栏
      showHistory: false, // 是否显示历史聊天记录
      lockMessage: false, // 是否锁定发送，
      showMinIdx: 0, // 下标低于showMinIdx的消息不显示，否则页面会很卡置
      quoteMessage: null, // 被引用的消息
      reqQueue: [],
      isSending: false,
      showAddGroupMember: false,
      shareMsgInfo: null,
      topDivHeight: 500, // 默认高度
      bottomDivHeight: 300, // 默认高度
      isDragging: false,
    };
  },
  methods: {
    shareMultiple() {
      console.log(this.radioArray, ",,,radioArray");
      console.log(this.chat, ",,,chat");
      const matched = [];
      this.chat.messages.forEach((item) => {
        if (item.id) {
          if (this.radioArray.includes(item.id)) {
            matched.push(item);
          }
        }
      });
      //0424
      console.log(matched, "????matched");
      this.openShareFriend(matched);
      this.deleteMultiple();
    },
    deleteMultiple() {
      this.radioArray = [];
      this.$store.commit("setMultiple", false);
    },
    startDrag(event) {
      console.log(event, "startDrag");
      this.isDragging = true;
      document.addEventListener("mousemove", this.onDrag);
      document.addEventListener("mouseup", this.stopDrag);
    },
    onDrag(event) {
      //   console.log(event, "onDrag");
      if (!this.isDragging) return;
      const containerHeight = 800; // 容器高度
      const y = event.clientY - this.$el.getBoundingClientRect().top;
      if (y > 0 && y < containerHeight) {
        // this.topDivHeight = containerHeight - y  < 200 ? 200 : y;
        this.bottomDivHeight =
          containerHeight - y - 10 < 200
            ? 200
            : containerHeight - y - 10 > 450
            ? 450
            : containerHeight - y - 10; // 减去 resizer 高度
      }
    },
    stopDrag(event) {
      console.log(event, ",,stopDrag,");

      this.isDragging = false;

      document.removeEventListener("mousemove", this.onDrag);
      document.removeEventListener("mouseup", this.stopDrag);
    },
    deleteMyMessage() {
      this.$confirm("清空自己发的消息（双方），确认清空吗？", "确认清空?", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        this.$store.dispatch("removeSocketPrivateChatMessage", {
          sendId: this.chat.targetId,
          slef: true,
        });
        this.$message.success("操作成功");
        this.$http({
          url: `/im/message/private/delete/${this.chat.targetId}`,
          method: "post",
        });
      });
    },
    changeBurn() {
      this.$store.dispatch("setChecked"); // 触发 mutation 修改 state
    },
    showMessageAndBurn(msgId) {
      let targetId = this.chat.targetId;
      let type = this.chat.type;
      console.log(type);

      // 调用方法，id，类型
      this.$store.dispatch("showMessageAndBurn", { type, targetId, msgId });
      this.$http({
        url: `/im/message/${type.toLowerCase()}/onMessageClick?messageId=${msgId}`,
        method: "put",
      });
    },
    moveChatToTop() {
      let chatIdx = this.$store.getters.findChatIdx(this.chat);
      this.$store.commit("moveTop", chatIdx);
    },
    closeRefBox() {
      this.$refs.emoBox.close();
      this.activeMessageIdx = -1;

      // this.$refs.atBox.close();
    },
    onCall(type) {
      if (type == this.$enums.MESSAGE_TYPE.ACT_RT_VOICE) {
        this.showPrivateVideo("voice");
      } else if (type == this.$enums.MESSAGE_TYPE.ACT_RT_VIDEO) {
        this.showPrivateVideo("video");
      }
    },
    onSwitchReceipt() {
      this.isReceipt = !this.isReceipt;
      this.refreshPlaceHolder();
    },
    onImageSuccess(data, file) {
      let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
      msgInfo.content = JSON.stringify(data);
      msgInfo.receipt = this.isReceipt;
      this.sendMessageRequest(msgInfo).then((m) => {
        msgInfo.loadStatus = "ok";
        msgInfo.id = m.id;
        this.isReceipt = false;
        this.$store.commit("insertMessage", [msgInfo, this.chat]);
      });
    },
    onImageFail(e, file) {
      let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
      msgInfo.loadStatus = "fail";
      this.$store.commit("insertMessage", [msgInfo, this.chat]);
    },
    onImageBefore(file) {
      let url = URL.createObjectURL(file);
      let data = {
        originUrl: url,
        thumbUrl: url,
      };
      let msgInfo = {
        id: 0,
        tmpId: this.generateId(),
        fileId: file.uid,
        sendId: this.mine.id,
        content: JSON.stringify(data),
        sendTime: new Date().getTime(),
        selfSend: true,
        type: this.$enums.MESSAGE_TYPE.IMAGE,
        readedCount: 0,
        loadStatus: "loading",
        status: this.$enums.MESSAGE_STATUS.UNSEND,
      };
      // 填充对方id
      this.fillTargetId(msgInfo, this.chat.targetId);
      // 插入消息
      this.$store.commit("insertMessage", [msgInfo, this.chat]);
      // 会话置顶
      this.moveChatToTop();
      // 滚动到底部
      this.scrollToBottom();
      // 借助file对象保存
      file.msgInfo = msgInfo;
    },
    onFileSuccess(url, file) {
      let data = {
        name: file.name,
        size: file.size,
        url: url,
      };
      let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
      msgInfo.content = JSON.stringify(data);
      msgInfo.receipt = this.isReceipt;
      this.sendMessageRequest(msgInfo).then((m) => {
        msgInfo.loadStatus = "ok";
        msgInfo.id = m.id;
        this.isReceipt = false;
        this.refreshPlaceHolder();
        this.$store.commit("insertMessage", [msgInfo, this.chat]);
      });
    },
    onFileFail(e, file) {
      let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
      msgInfo.loadStatus = "fail";
      this.$store.commit("insertMessage", [msgInfo, this.chat]);
    },
    onFileBefore(file) {
      let url = URL.createObjectURL(file);
      let data = {
        name: file.name,
        size: file.size,
        url: url,
      };
      let msgInfo = {
        id: 0,
        tmpId: this.generateId(),
        sendId: this.mine.id,
        content: JSON.stringify(data),
        sendTime: new Date().getTime(),
        selfSend: true,
        type: this.$enums.MESSAGE_TYPE.FILE,
        loadStatus: "loading",
        readedCount: 0,
        status: this.$enums.MESSAGE_STATUS.UNSEND,
      };
      // 填充对方id
      this.fillTargetId(msgInfo, this.chat.targetId);
      // 插入消息
      this.$store.commit("insertMessage", [msgInfo, this.chat]);
      // 会话置顶
      this.moveChatToTop();
      // 滚动到底部
      this.scrollToBottom();
      // 借助file对象透传
      file.msgInfo = msgInfo;
    },
    onVideoSuccess(data, file) {
      let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
      msgInfo.content = JSON.stringify(data);
      msgInfo.receipt = this.isReceipt;
      this.sendMessageRequest(msgInfo).then((m) => {
        msgInfo.loadStatus = "ok";
        msgInfo.id = m.id;
        this.isReceipt = false;
        this.$store.commit("insertMessage", [msgInfo, this.chat]);
      });
    },
    onVideoFail(e, file) {
      let msgInfo = JSON.parse(JSON.stringify(file.msgInfo));
      msgInfo.loadStatus = "fail";
      this.$store.commit("insertMessage", [msgInfo, this.chat]);
    },
    onVideoBefore(file) {
      let url = URL.createObjectURL(file);
      let data = {
        videoUrl: url,
      };
      let msgInfo = {
        id: 0,
        tmpId: this.generateId(),
        sendId: this.mine.id,
        content: JSON.stringify(data),
        sendTime: new Date().getTime(),
        selfSend: true,
        type: this.$enums.MESSAGE_TYPE.VIDEO,
        loadStatus: "loading",
        readedCount: 0,
        status: this.$enums.MESSAGE_STATUS.UNSEND,
      };
      // 填充对方id
      this.fillTargetId(msgInfo, this.chat.targetId);
      // 插入消息
      this.$store.commit("insertMessage", [msgInfo, this.chat]);
      // 会话置顶
      this.moveChatToTop();
      // 滚动到底部
      this.scrollToBottom();
      // 借助file对象透传
      file.msgInfo = msgInfo;
    },
    onCloseSide() {
      this.showSide = false;
    },
    onScroll(e) {
      let scrollElement = e.target;
      let scrollTop = scrollElement.scrollTop;
      if (scrollTop < 30) {
        // 在顶部,不滚动的情况
        // 多展示20条信息
        this.showMinIdx = this.showMinIdx > 20 ? this.showMinIdx - 20 : 0;
      }
    },
    showEmotionBox() {
      let width = this.$refs.emotion.offsetWidth;
      let left = this.$elm.fixLeft(this.$refs.emotion);
      let top = this.$elm.fixTop(this.$refs.emotion);
      this.$refs.emoBox.open({
        x: left + width / 2,
        y: top,
      });
    },
    onEmotion(emoText) {
      this.$refs.chatInputEditor.insertEmoji(emoText);
    },
    showRecordBox() {
      this.showRecord = true;
    },
    closeRecordBox() {
      this.showRecord = false;
    },
    showPrivateVideo(mode) {
      if (!this.isFriend) {
        this.$message.error("你已不是对方好友,无法呼叫");
        return;
      }
      let rtcInfo = {
        mode: mode,
        isHost: true,
        friend: this.friend,
      };
      // 通过home.vue打开单人视频窗口
      this.$eventBus.$emit("openPrivateVideo", rtcInfo);
    },
    onGroupVideo() {
      this.$http({
        url: "/im/webrtc/group/info?groupId=" + this.group.id,
        method: "GET",
      }).then((rtcInfo) => {
        if (rtcInfo.isChating) {
          // 已在通话中，可以直接加入通话
          this.$refs.rtcJoin.open(rtcInfo);
        } else {
          // 邀请成员发起通话
          let ids = [this.mine.id];
          let maxChannel = this.$store.state.configStore.webrtc.maxChannel;
          this.$refs.rtcSel.open(maxChannel, ids, ids, []);
        }
      });
    },
    onInviteOk(members) {
      if (members.length < 2) {
        return;
      }
      let userInfos = [];
      members.forEach((m) => {
        userInfos.push({
          id: m.userId,
          nickname: m.showNickName,
          headImage: m.headImage,
          avatarThumb: m.avatarThumb,
          isCamera: false,
          isMicroPhone: true,
        });
      });
      let rtcInfo = {
        isHost: true,
        groupId: this.group.id,
        inviterId: this.mine.id,
        userInfos: userInfos,
      };
      // 通过home.vue打开多人视频窗口
      this.$eventBus.$emit("openGroupVideo", rtcInfo);
    },
    showHistoryBox() {
      this.showHistory = true;
    },
    closeHistoryBox() {
      this.showHistory = false;
    },
    onSendRecord(data) {
      let msgInfo = {
        content: JSON.stringify(data),
        type: 3,
        receipt: this.isReceipt,
      };
      // 填充对方id
      this.fillTargetId(msgInfo, this.chat.targetId);
      this.sendMessageRequest(msgInfo).then((m) => {
        m.selfSend = true;
        this.$store.commit("insertMessage", [m, this.chat]);
        // 会话置顶
        this.moveChatToTop();
        // 保持输入框焦点
        this.$refs.chatInputEditor.focus();
        // 滚动到底部
        this.scrollToBottom();
        // 关闭录音窗口
        this.showRecord = false;
        this.isReceipt = false;
        this.refreshPlaceHolder();
      });
    },
    fillTargetIdForwarding(msgInfo, targetId, type) {
      if (type == "GROUP") {
        msgInfo.groupId = targetId;
      } else {
        msgInfo.recvId = targetId;
      }
    },
    fillTargetId(msgInfo, targetId) {
      if (this.chat.type == "GROUP") {
        msgInfo.groupId = targetId;
      } else {
        msgInfo.recvId = targetId;
      }
    },
    notifySend() {
      this.$refs.chatInputEditor.submit();
    },
    async sendMessage(fullList) {
      this.resetEditor();
      this.readedMessage();
      let sendText = this.isReceipt ? "【回执消息】" : "";
      let promiseList = [];
      for (let i = 0; i < fullList.length; i++) {
        let msg = fullList[i];
        switch (msg.type) {
          case "text":
            await this.sendTextMessage(sendText + msg.content, msg.atUserIds);
            break;
          case "image":
            await this.sendImageMessage(msg.content.file);
            break;
          case "file":
            await this.sendFileMessage(msg.content.file);
            break;
        }
      }
    },
    sendImageMessage(file) {
      return new Promise((resolve, reject) => {
        this.onImageBefore(file);
        let formData = new FormData();
        formData.append("multipart", file);
        formData.append("model", "im");
        formData.append("pid", 0);
        this.$http
          .post("/user/upload/image", formData, {
            headers: {
              "Content-Type": "multipart/form-data",
            },
          })
          .then((data) => {
            this.onImageSuccess(data, file);
            resolve();
          })
          .catch((res) => {
            this.onImageFail(res, file);
            reject();
          });
        this.$nextTick(() => this.$refs.chatInputEditor.focus());
        this.scrollToBottom();
      });
    },
    sendTextMessage(sendText, atUserIds) {
      return new Promise((resolve, reject) => {
        if (!sendText.trim()) {
          reject();
        }
        let msgInfo = {
          content: sendText,
          type: 0,
        };
        // 填充对方id
        this.fillTargetId(msgInfo, this.chat.targetId);
        // 被@人员列表
        if (this.chat.type == "GROUP") {
          msgInfo.atUserIds = atUserIds;
          msgInfo.receipt = this.isReceipt;
        }
        // 引用消息
        if (this.quoteMessage) {
          msgInfo.quoteMessageId = this.quoteMessage.id;
        }
        this.lockMessage = true;
        this.sendMessageRequest(msgInfo)
          .then((m) => {
            m.selfSend = true;
            console.log(m);
            console.log(this.chat);
            this.$store.commit("insertMessage", [m, this.chat]);
            // 会话置顶
            this.moveChatToTop();
          })
          .finally(() => {
            // 解除锁定
            this.scrollToBottom();
            this.isReceipt = false;
            this.quoteMessage = null;
            resolve();
          });
      });
    },
    sendFileMessage(file) {
      return new Promise((resolve, reject) => {
        let check = this.$refs.fileUpload.beforeUpload(file);
        if (check) {
          this.$refs.fileUpload.onFileUpload({ file });
        }
      });
    },
    async clipboardImg(url) {
      try {
        const data = await fetch(url);
        const blob = await data.blob();
        await navigator.clipboard.write([
          new window.ClipboardItem({
            [blob.type]: blob,
          }),
        ]);
        this.$message.success("已复制");
      } catch (err) {
        this.$message.success("复制失败");
      }
    },
    downloadMessage(msgInfo) {
      console.log(msgInfo, "msgInfo,,,,");

      const file = JSON.parse(msgInfo.content);
      const url =
        msgInfo.type == this.$enums.MESSAGE_TYPE.IMAGE
          ? file.url
          : msgInfo.type == this.$enums.MESSAGE_TYPE.VIDEO
          ? file.url
          : msgInfo.type == this.$enums.MESSAGE_TYPE.FILE
          ? file.url.url
          : file.url;
      const savePath =
        "downloads/" + msgInfo.type == this.$enums.MESSAGE_TYPE.IMAGE
          ? file.fileName
          : msgInfo.type == this.$enums.MESSAGE_TYPE.VIDEO
          ? file.fileName
          : msgInfo.type == this.$enums.MESSAGE_TYPE.FILE
          ? file.url.fileName
          : file.fileName;
      console.log(file, "file", savePath, "savePath", url, "url");

      this.$ipcRenderer.send("start-download", {
        url,
        savePath, // 相对路径或绝对路径
        file,
      });
      // 监听下载完成
      this.$ipcRenderer.once("download-complete", () => {
        this.$message.success("下载成功");
        // ipcRenderer.removeAllListeners('download-progress')
      });
    },
    openShareFriend(msgInfo) {
      console.log(msgInfo, "openShareFriend");
      this.shareMsgInfo = msgInfo;
      this.showAddGroupMember = true;
    },
    shareMessage(user) {
      console.log(user, this.shareMsgInfo, "share-function???user");

      let type = user.userType;
      let chat = {
        type,
        targetId: user.id,
        showName: user.nickname,
        headImage: user.avatar,
        avatar: user.avatar,
        avatarThumb: user.avatarThumb,
      };
      this.$store.commit("openChat", chat);
      this.$store.commit("activeChat", 0);

      return new Promise((resolve, reject) => {
        let shareMsgInfo = this.shareMsgInfo;

        let msgInfo = {
          content: shareMsgInfo.content,
          type: shareMsgInfo.type,
        };
        console.log(msgInfo, "msgInfo-shareMessage");

        // 填充对方id,使用转发的方法
        this.fillTargetIdForwarding(msgInfo, user.id, type);
        this.lockMessage = true;
        this.sendMessageRequest(msgInfo, type)
          .then((m) => {
            m.selfSend = true;
            this.$store.commit("insertMessage", [m, this.chat]);
            // 会话置顶
            this.moveChatToTop();
          })
          .finally(() => {
            // 解除锁定
            this.scrollToBottom();
            this.isReceipt = false;
            resolve();
          });
      });
    },
    onCloseAddGroupMember() {
      this.showAddGroupMember = false;
    },
    async copyMessage(msgInfo) {
      if (msgInfo.type == 1) {
        // 图片
        let content = JSON.parse(msgInfo.content);
        let url = content.url;
        var canvas = document.createElement("canvas"); // 创建一个画板
        let image = new Image();
        image.setAttribute("crossOrigin", "Anonymous"); //可能会有跨越问题
        image.src = url;
        image.onload = () => {
          // img加载完成事件
          canvas.width = image.width; //设置画板宽度
          canvas.height = image.height; //设置画板高度
          canvas.getContext("2d").drawImage(image, 0, 0); //加载img到画板
          let url = canvas.toDataURL("image/png"); // 转换图片为dataURL，格式为png
          this.clipboardImg(url); // 调用复制方法
        };
      } else if (msgInfo.type == 2) {
        try {
          const file = JSON.parse(msgInfo.content).url;
          const response = await fetch(file.url);
          const result = await window.electronAPI.copyFileToClipboard(response);
        } catch (error) {
          console.log("🚀🚀🚀 ~ copyMessage ~ error:", error);
        }
      } else {
        // 复制消息
        const text = msgInfo.content;
        const input = document.createElement("input");
        input.value = text;
        document.body.appendChild(input);
        input.select();
        document.execCommand("copy");
        document.body.removeChild(input);
        this.$message.success("文字已复制");
      }
    },
    async convertVideoFormat(blob) {
      // 使用 WebCodecs API 转换格式
      const track = await navigator.mediaDevices.getUserMedia({ video: true });
      const mediaRecorder = new MediaRecorder(track, {
        mimeType: "video/webm;codecs=vp9",
      });

      return new Promise((resolve, reject) => {
        mediaRecorder.ondataavailable = async (e) => {
          resolve(new Blob([e.data], { type: "video/webm" }));
        };

        mediaRecorder.start();
        setTimeout(() => {
          mediaRecorder.stop();
          track.getTracks().forEach((t) => t.stop());
        }, 1000);
      });
    },
    deleteMessage(msgInfo) {
      this.$confirm("确认删除消息?", "删除消息", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        this.$store.commit("deleteMessage", [msgInfo, this.chat]);
      });
    },
    recallMessage(msgInfo) {
      this.$confirm("确认撤回消息?", "撤回消息", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        let url = `/im/message/${this.chat.type.toLowerCase()}/recall/${
          msgInfo.id
        }`;
        this.$http({
          url: url,
          method: "delete",
        }).then(() => {
          this.$message.success("消息已撤回");
          msgInfo = JSON.parse(JSON.stringify(msgInfo));
          msgInfo.type = 10;
          msgInfo.content = "你撤回了一条消息";
          msgInfo.status = this.$enums.MESSAGE_STATUS.RECALL;
          this.$store.commit("insertMessage", [msgInfo, this.chat]);
        });
      });
    },
    onQuoteMessage(msgInfo) {
      this.quoteMessage = msgInfo;
    },
    onLocateQuoteMessage(msgInfo) {
      // 寻找消息位置
      // const idx = this.findMessageIdx(msgInfo.quoteMessage);
      // if (idx < 0) {
      // 	this.$message.error("无法定位原消息");
      // 	return;
      // }
      // // 要定位到消息，首先要渲染这条消息
      // this.showMinIdx = Math.min(this.showMinIdx, Math.max(idx - 10, 0));
      // this.$nextTick(() => {
      // 	document.getElementById(msgInfo.quoteMessage.id).scrollIntoView({ behavior: 'smooth' });
      // 	this.activeMessageIdx = idx;
      // })

      const idx = this.findMessageIdx(msgInfo.quoteMessage);
      if (idx < 0) {
        this.$message.error("无法定位原消息");
        return;
      }
      // 要定位到消息，首先要渲染这条消息
      this.$nextTick(() => {
        document
          .getElementById(msgInfo.quoteMessage.id)
          .scrollIntoView({ behavior: "smooth" });
        this.activeMessageIdx = msgInfo.quoteMessage.id;
      });
    },
    findMessageIdx(msgInfo) {
      for (let idx in this.chat.messages) {
        const message = this.chat.messages[idx];
        // 通过id判断
        if (msgInfo.id && message.id && message.id == msgInfo.id) {
          return idx;
        }
        // 正在发送中的消息可能没有id,只有tmpId
        if (msgInfo.tmpId && message.tmpId && message.tmpId == msgInfo.tmpId) {
          return idx;
        }
      }
      return -1;
    },
    readedMessage() {
      if (this.chat.unreadCount == 0) {
        return;
      }
      this.$store.commit("resetUnreadCount", this.chat);
      if (this.chat.type == "GROUP") {
        var url = `/im/message/group/readed?groupId=${this.chat.targetId}`;
      } else {
        url = `/im/message/private/readed?friendId=${this.chat.targetId}`;
      }
      this.$http({
        url: url,
        method: "put",
      }).then(() => {});
    },
    loadReaded(fId) {
      this.$http({
        url: `/im/message/private/maxReadedId?friendId=${fId}`,
        method: "get",
      }).then((id) => {
        this.$store.commit("readedMessage", {
          friendId: fId,
          maxId: id,
        });
      });
    },
    loadGroup(groupId) {
      this.$http({
        url: `/im/group/find/${groupId}`,
        method: "get",
      }).then((group) => {
        // console.log(group.avatarThumb)
        this.group = group;
        this.$store.commit("updateChatFromGroup", group);
        this.$store.commit("updateGroup", group);
      });
      this.$http({
        url: `/im/group/members/${groupId}`,
        method: "get",
      }).then((groupMembers) => {
        this.groupMembers = groupMembers;
      });
    },
    loadFriend(friendId) {
      // 获取对方最新信息
      this.$http({
        url: `/im/friend/find/${friendId}`,
        method: "get",
      }).then((friend) => {
        this.friend = friend;
        this.userInfo = friend;
        this.$store.commit("updateChatFromFriend", friend);
        this.$store.commit("updateFriend", friend);
      });
    },
    // loadFriend(friendId) {
    // 	// 获取好友信息
    // 	this.$http({
    // 		url: `/user/find/${friendId}`,
    // 		method: 'GET'
    // 	}).then((userInfo) => {
    // 		this.userInfo = userInfo;
    // 		this.updateFriendInfo();
    // 	})
    // },
    showName(msgInfo) {
      if (!msgInfo) return "";
      if (this.chat.type == "GROUP") {
        let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
        return member ? member.showNickName : "";
      } else {
        return msgInfo.sendId == this.mine.id
          ? this.mine.nickname
          : this.chat.showName;
      }
    },
    headImage(msgInfo) {
      if (this.chat.type == "GROUP") {
        let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
        return member ? member.avatarThumb : "";
      } else {
        let avatarThumb =
          msgInfo.sendId == this.mine.id
            ? this.mine.avatarThumb
            : this.chat.avatarThumb;
        return !avatarThumb ? "" : avatarThumb;
      }
    },
    resetEditor() {
      this.$nextTick(() => {
        this.$refs.chatInputEditor.clear();
        this.$refs.chatInputEditor.focus();
      });
    },
    scrollToBottom() {
      this.$nextTick(() => {
        let div = document.getElementById("chatScrollBox");
        div.scrollTop = div.scrollHeight;
      });
    },
    refreshPlaceHolder() {
      if (this.isReceipt) {
        this.placeholder = "【回执消息】";
      } else if (this.$refs.editBox && this.$refs.editBox.innerHTML) {
        this.placeholder = "";
      } else {
        this.placeholder = "聊点什么吧~";
      }
    },
    sendMessageRequest(msgInfo, type) {
      return new Promise((resolve, reject) => {
        // 请求入队列，防止请求"后发先至"，导致消息错序
        this.reqQueue.push({ msgInfo, resolve, reject });
        this.processReqQueue(type);
      });
    },
    processReqQueue(type) {
      if (this.reqQueue.length && !this.isSending) {
        this.isSending = true;
        const reqData = this.reqQueue.shift();
        let url = this.messageAction;
        if (type) {
          url = `/im/message/${type.toLowerCase()}/send`;
        }
        reqData.msgInfo.burn = this.$store.state.chatStore.checked;
        this.$http({
          url,
          method: "post",
          data: reqData.msgInfo,
        })
          .then((res) => {
            reqData.resolve(res);
          })
          .catch((e) => {
            reqData.reject(e);
          })
          .finally(() => {
            this.isSending = false;
            // 发送下一条请求
            this.processReqQueue();
          });
      }
    },
    showBannedTip() {
      let msgInfo = {
        tmpId: this.generateId(),
        sendId: this.mine.id,
        sendTime: new Date().getTime(),
        type: this.$enums.MESSAGE_TYPE.TIP_TEXT,
      };
      if (this.chat.type == "PRIVATE") {
        msgInfo.recvId = this.mine.id;
        msgInfo.content = "该用户已被管理员封禁,原因:" + this.userInfo.reason;
      } else {
        msgInfo.groupId = this.group.id;
        msgInfo.content = "本群聊已被管理员封禁,原因:" + this.group.reason;
      }
      this.$store.commit("insertMessage", [msgInfo, this.chat]);
    },
    generateId() {
      // 生成临时id
      return (
        String(new Date().getTime()) + String(Math.floor(Math.random() * 1000))
      );
    },
  },
  computed: {
    isOwner() {
      return this.group.ownerId == this.$store.state.userStore.userInfo.id;
    },
    mine() {
      return this.$store.state.userStore.userInfo;
    },
    isFriend() {
      let friends = this.$store.state.friendStore.friends;
      return friends.some((f) => f.id == this.userInfo.id);
    },
    // friend() {
    // 	let friends = this.$store.state.friendStore.friends;
    // 	return friends.find((f) => f.id == this.userInfo.id);
    // },
    title() {
      let title = this.chat.showName;
      if (this.chat.type == "GROUP") {
        let size = this.groupMembers.filter((m) => !m.quit).length;
        title += `(${size})`;
      }
      return title;
    },
    messageAction() {
      return `/im/message/${this.chat.type.toLowerCase()}/send`;
    },
    unreadCount() {
      return this.chat.unreadCount;
    },
    messageSize() {
      if (!this.chat || !this.chat.messages) {
        return 0;
      }
      return this.chat.messages.length;
    },
    isBanned() {
      return (
        (this.chat.type == "PRIVATE" && this.userInfo.isBanned) ||
        (this.chat.type == "GROUP" && this.group.isBanned)
      );
    },
    isMultiple() {
      return this.$store.state.chatStore.isShowMultiple;
    },
  },
  watch: {
    chat: {
      handler(newChat, oldChat) {
        if (
          newChat.targetId > 0 &&
          (!oldChat ||
            newChat.type != oldChat.type ||
            newChat.targetId != oldChat.targetId)
        ) {
          if (this.chat.type == "GROUP") {
            this.loadGroup(this.chat.targetId);
          } else {
            this.loadFriend(this.chat.targetId);
            // 加载已读状态
            this.loadReaded(this.chat.targetId);
          }
          // 滚到底部
          this.scrollToBottom();
          this.showSide = false;
          // 消息已读
          this.readedMessage();
          // 初始状态只显示30条消息
          let size = this.chat.messages.length;
          this.showMinIdx = size > 30 ? size - 30 : 0;
          // 重置输入框
          this.resetEditor();
          // 复位回执消息
          this.isReceipt = false;
          // 清空引用消息
          this.quoteMessage = null;
          // 更新placeholder
          this.refreshPlaceHolder();
        }
      },
      immediate: true,
    },
    messageSize: {
      handler(newSize, oldSize) {
        if (newSize > oldSize) {
          // 拉至底部
          this.scrollToBottom();
        }
      },
    },
  },
  mounted() {
    let div = document.getElementById("chatScrollBox");
    div.addEventListener("scroll", this.onScroll);
  },
};
</script>

<style lang="scss">
.hiddenLabel {
  visibility: hidden;
}
.checkboxx {
  position: absolute;
  top: 50%;
  left: -8px;
  transform: translate(-50%, -4px);
}
.chat-box {
  position: relative;
  width: 100%;
  background: #fff;

  .el-header {
    display: flex;
    justify-content: space-between;
    padding: 0 12px;
    line-height: 50px;
    font-size: var(--im-font-size-larger);
    border-bottom: var(--im-border);

    .btn-side {
      position: absolute;
      right: 120px;
      top: -5px;
      line-height: 50px;
      font-size: 20px;
      cursor: pointer;
      color: var(--im-text-color-light);
    }
  }

  .im-chat-main {
    padding: 0;
    background-color: #fff;

    .im-chat-box {
      > ul {
        padding: 0 20px;

        li {
          list-style-type: none;
        }
      }
    }
  }

  .im-chat-footer {
    display: flex;
    flex-direction: column;
    padding: 0;
    position: relative;
    .chat-tool-bar {
      cursor: ns-resize;

      display: flex;
      position: relative;
      width: 100%;
      height: 36px;
      text-align: left;
      box-sizing: border-box;
      border-top: var(--im-border);
      padding: 4px 2px 2px 8px;
      .btn-box {
        height: 70px;
        width: 70px;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        .el-button {
          flex: 1;
        }
        > span {
          font-size: 14px;
          color: #000;
          font-weight: bold;
        }
      }
      > div {
        font-size: 22px;
        cursor: pointer;
        line-height: 30px;
        width: 30px;
        height: 30px;
        text-align: center;
        border-radius: 2px;
        margin-right: 8px;
        color: #999;
        transition: 0.3s;

        &.chat-tool-active {
          font-weight: 600;
          color: var(--im-color-primary);
          background-color: #ddd;
        }
      }

      > div:hover {
        color: #333;
      }

      > div.huo_active {
        color: red;
      }

      > div.shannon-huo:hover {
        color: red;
      }
    }

    .send-content-area {
      position: relative;
      display: flex;
      flex-direction: column;
      height: 100%;
      background-color: white !important;

      .send-text-area {
        box-sizing: border-box;
        padding: 5px;
        width: 100%;
        flex: 1;
        resize: none;
        font-size: 16px;
        outline: none;

        text-align: left;
        line-height: 30px;

        &:before {
          content: attr(placeholder);
          color: gray;
        }

        .at {
          color: blue;
          font-weight: 600;
        }

        .receipt {
          color: darkblue;
          font-size: 15px;
          font-weight: 600;
        }

        .emo {
          width: 30px;
          height: 30px;
          vertical-align: bottom;
        }
      }

      .send-image-area {
        text-align: left;
        border: #53a0e7 solid 1px;

        .send-image-box {
          position: relative;
          display: inline-block;

          .send-image {
            max-height: 180px;
            border: 1px solid #ccc;
            border-radius: 2%;
            margin: 2px;
          }

          .send-image-close {
            position: absolute;
            padding: 3px;
            right: 7px;
            top: 7px;
            color: white;
            cursor: pointer;
            font-size: 15px;
            font-weight: 600;
            background-color: #aaa;
            border-radius: 50%;
            border: 1px solid #ccc;
          }
        }
      }

      .quote-message {
        position: absolute;
        bottom: 10px;
        left: 10px;
        font-size: 14px;
        max-width: 80%;
        border-radius: 5px;

        &:hover .quote-remove {
          display: block;
        }

        .quote-remove {
          display: none;
          position: absolute;
          top: -8px;
          right: -8px;
          width: 20px;
          height: 20px;
          line-height: 20px;
          font-size: 14px;
          color: white;
          border-radius: 50%;
          background: #aaa;
          cursor: pointer;

          &:hover {
            background: #888;
          }
        }
      }

      .send-btn-area {
        padding: 10px;
        position: absolute;
        bottom: 4px;
        right: 6px;
      }
    }
  }

  .chat-group-side-box {
    border-left: var(--im-border);
  }
  .draggable {
    min-height: 300px !important;
    //   background-color: #a3c1ad;
    text-align: center;
    //   cursor: ew-resize;
    transition: height 0.2s;
    // overflow-y: hidden;
    // position: relative;
  }
}
</style>
